import os

from django.db import transaction
from django.http import HttpResponse, FileResponse
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.permissions import IsAuthenticated
from django.conf import settings
from service.models import PredictionFact, Month, Event, SpecDistribution
from rest_framework import filters, status, viewsets, mixins
from rest_framework.decorators import action
from rest_framework.response import Response
from service.serializers import PredictionFactSerializer, MonthSerializer, EmptySerializer, EventSerializer, \
    EventPostSerializer, ReportRequestSerializer
from service.serializers import PredictionFactSerializer, MonthSerializer, EmptySerializer, EventSerializer, EventPostSerializer, SpecDistributionSerializer
from service.fill_service_data_from_xlsx import get_data_from_xlsx
from service.prediction_service import PredictionService
from service.report_generator import PredictionReportGenerator, ScheduleReportGenerator
from users.models import User
from users.permissions import IsDoctor, IsHR, IsChief, IsSelfDoctor
from service.shedule_optimisation.optimiser import Optimiser
from rest_framework.permissions import AllowAny


def index(request):
    return HttpResponse("Hello, world.")


def fill_data(request):
    get_data_from_xlsx()
    return HttpResponse("Sucess")


def predict(request):
    PredictionService().predict_data()
    return HttpResponse("Sucess")


class PredictionFactViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = PredictionFact.objects.all()
    serializer_class = PredictionFactSerializer


class MonthViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Month.objects.all()
    serializer_class = MonthSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['month', 'year', 'status']
    permission_classes = [AllowAny]

    @action(detail=True, methods=['post'])
    def approve_month(self, request, pk=None):
        month = self.get_object()
        if month.status in ['not_approved', 'temporary']:
            with transaction.atomic():
                old_approved_months = Month.objects.filter(year=month.year, month=month.month,
                                                           status='approved')
                if old_approved_months.exists():
                    old_approved_months.delete()

                Month.objects.filter(id=month.id).update(status='approved')
                Event.objects.filter(month=month, kind='work_delta').update(kind='work_time')
                Event.objects.filter(month=month).update(viewed=True)
            return Response({'status': 'Success'}, status=status.HTTP_200_OK)
        else:
            return Response({'status': 'Month is not in "not_approved" or in "temporary" status'},
                            status=status.HTTP_400_BAD_REQUEST)


    @action(detail=True, methods=['get'])
    def optimize(self, request, pk=None):
        month = self.get_object()
        Optimiser(month).optimise_work()
        return Response({'status': 'Schedule optimised'})

    @action(detail=True, methods=['post'])
    def create_events(self, request, pk=None):
        month = self.get_object()
        month.create_events()
        return Response({'status': 'events created'})

    @action(detail=True, methods=['post'])
    def recreate_events(self, request, pk=None):
        month = self.get_object()
        month.recreate_events()
        return Response({'status': 'events recreated'})

    @action(detail=True, methods=['post'], permission_classes=[IsDoctor | IsHR | IsChief])
    def recreate_events(self, request, pk=None):
        month = self.get_object()
        user_id = request.data.get('user_id')
        if user_id:
            try:
                user = User.objects.get(pk=user_id)
            except User.DoesNotExist:
                return Response({'status': 'user not found'}, status=status.HTTP_404_NOT_FOUND)
            # Дополнительная проверка для врачей, чтобы они могли создавать события только для себя
            if request.user.groups.filter(name='Врачи').exists() and request.user != user:
                return Response({'status': 'You can only create events for yourself'},
                                status=status.HTTP_403_FORBIDDEN)
            month.create_events(user=user)
        else:
            month.create_events()
        return Response({'status': 'events created'})


class EventViewSet(viewsets.ModelViewSet):
    queryset = Event.objects.all()
    # serializer_class = EventSerializer
    filter_backends = [DjangoFilterBackend]
    permission_classes = [AllowAny]
    filterset_fields = ['kind', 'month', 'day', 'user', 'viewed']

    def get_serializer_class(self):
        if self.request.method == 'POST':
            return EventPostSerializer
        return EventSerializer

    def create(self, request, *args, **kwargs):
        month = request.data.get('month')
        try:
            month = Month.objects.get(id=month)
        except Month.DoesNotExist:
            return Response({'status': 'month not found'}, status=status.HTTP_404_NOT_FOUND)

        request_data = request.data.copy()

        with transaction.atomic():
            if month.status in ['not_approved', 'temporary']:
                request_data['month'] = month.id
                temp_month = month
            else:
                temp_month, created = Month.objects.get_or_create(
                    year=month.year,
                    month=month.month,
                    status='temporary'
                )
                if created:
                    self._copy_events_and_prediction_facts(month, temp_month)
                request_data['month'] = temp_month.id

            request_data['viewed'] = False

            if not Event.objects.filter(**request.data).exists():
                response = super().create(request, *args, **kwargs)
                return response
            else:
                return Response({'message': 'Event exists'}, status=status.HTTP_400_BAD_REQUEST)

    def _copy_events_and_prediction_facts(self, source_month, target_month):
        event_fields = [f.name for f in Event._meta.get_fields()]
        event_fields.remove('id')
        events = list(source_month.events.values(*event_fields))
        for ev in events:
            ev['month_id'] = target_month.id
            ev.pop('month')
            ev['user_id'] = ev.pop('user')
            Event.objects.get_or_create(**ev)

        for predictionfact in PredictionFact.objects.filter(month=source_month).all():
            PredictionFact.objects.create(
                specialization=predictionfact.specialization,
                week=predictionfact.week,
                qtty=predictionfact.qtty,
                qtty_predicted=predictionfact.qtty_predicted,
                month=target_month
            )
        # week_fields = [f.name for f in PredictionFact._meta.get_fields()]
        # week_fields.remove('id')
        # weeks = list(source_month.weeks.values(*week_fields))
        # for week in weeks:
        #     week['month_id'] = target_month.id
        #     week.pop('month')
        #     week['specialization_id'] = week.pop('specialization')
        #     PredictionFact.objects.get_or_create(**week)

    @action(detail=False, methods=['get'])
    def new_events(self, request):
        event_types = ('time_off', 'sick', 'vacation')
        events = Event.objects.filter(kind__in=event_types, viewed=False)
        serializer = self.get_serializer(events, many=True)
        return Response(serializer.data)


class BaseReportGeneratorViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = ReportRequestSerializer
    report_generator_class = None
    report_filename_prefix = ""

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        year = serializer.validated_data['year']
        month = serializer.validated_data['month']
        report_generator = self.report_generator_class(year, month)
        report_path = report_generator.generate_report()
        return FileResponse(open(report_path, 'rb'), as_attachment=True, filename=f"{self.report_filename_prefix}_{year}_{month}.xlsx")


class PredictionReportGeneratorViewSet(BaseReportGeneratorViewSet):
    report_generator_class = PredictionReportGenerator
    report_filename_prefix = "prediction_report"


class ScheduleReportGeneratorViewSet(BaseReportGeneratorViewSet):
    report_generator_class = ScheduleReportGenerator
    report_filename_prefix = "schedule_report"


class SpecDistributionViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = SpecDistribution.objects.all()
    serializer_class = SpecDistributionSerializer
